/*
RetroLeague - Mobile application for The Retro League Podcast
Copyright (C) 2010-2013 Hugues Johnson

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software 
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

package com.huguesjohnson.retroleague;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;

import android.app.AlertDialog;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;

import com.actionbarsherlock.app.ActionBar;
import com.actionbarsherlock.app.SherlockActivity;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import com.huguesjohnson.retroleague.StreamEntry.Sources;
import com.huguesjohnson.retroleague.episode.EpisodeParser;
import com.huguesjohnson.retroleague.forums.ForumParser;
import com.huguesjohnson.retroleague.rss.RssParser;
import com.huguesjohnson.retroleague.util.HttpFetch;
import com.huguesjohnson.retroleague.util.SerializationHelper;

public class StreamActivity extends SherlockActivity{
	private static final String TAG="StreamActivity";
	private AlertDialog aboutDialog;
	private StreamEntryArrayAdapter stream;
	private ListView listViewStream;
	private static StreamEntry selectedEntry;
	private static boolean isUpdating=false;
	private static long lastRefresh=0L;
	//menu constants
	private final static int MENU_REFRESH=0;
	private final static int MENU_SETTINGS=1;
	private final static int MENU_MANAGE_DOWNLOADS=2;
	private final static int MENU_ABOUT=3;
	private final static int MENU_QUIT=4;
	
	private class UpdateStreamTask extends AsyncTask<Void,Void,Void>{
		private static final String TAG="UpdateStreamTask";
		private ArrayList<StreamEntry> newEntries;
		private SharedPreferences prefs;
		
		@Override
		protected void onPreExecute(){
			prefs=getApplicationContext().getSharedPreferences("com.huguesjohnson.retroleague",MODE_PRIVATE);
		}
		
		@Override
		protected Void doInBackground(Void... params){
			Date mostRecent=stream.getMostRecent();
			newEntries=new ArrayList<StreamEntry>();
			int timeout=prefs.getInt(getString(R.string.prefkey_timeout),5000);
			//Podcast
			try{
				Log.v(TAG,"Calling podcast RSS: "+System.currentTimeMillis());
				InputStream in=HttpFetch.fetch(getString(R.string.rss_url),timeout);
				Log.v(TAG,"Parsing podcast RSS: "+System.currentTimeMillis());
				newEntries.addAll(EpisodeParser.parseEpisodeList(in,mostRecent));
				in.close();
				Log.v(TAG,"Done with podcast RSS: "+System.currentTimeMillis());
			}catch(Exception x){
				Log.e(TAG,"doInBackground - Podcast",x);
			}
			//HJ
			boolean getThis=prefs.getBoolean(getString(R.string.prefkey_show_hj),true);
			if(getThis){
				try{
					InputStream in=HttpFetch.fetch(getString(R.string.hj_rss),timeout);
					newEntries.addAll(RssParser.parseEntryList(in,mostRecent,Sources.HJ));
					in.close();
				}catch(Exception x){
					Log.e(TAG,"doInBackground - HJ",x);
				}
			}
			//YouTube
			getThis=prefs.getBoolean(getString(R.string.prefkey_show_youtube),true);
			if(getThis){
				try{
					InputStream in=HttpFetch.fetch(getString(R.string.youtube_rss),timeout);
					newEntries.addAll(RssParser.parseEntryList(in,mostRecent,Sources.YouTube));
					in.close();
				}catch(Exception x){
					Log.e(TAG,"doInBackground - YouTube",x);
				}
			}
			//Tumblr
			getThis=prefs.getBoolean(getString(R.string.prefkey_show_tumblr),true);
			if(getThis){
				try{
					InputStream in=HttpFetch.fetch(getString(R.string.tumblr_rss),timeout);
					newEntries.addAll(RssParser.parseEntryList(in,mostRecent,Sources.Tumblr));
					in.close();
				}catch(Exception x){
					Log.e(TAG,"doInBackground - Tumblr",x);
				}
				//Tumblr - HJ
				try{
					InputStream in=HttpFetch.fetch(getString(R.string.tumblr_hj_rss),timeout);
					newEntries.addAll(RssParser.parseEntryList(in,mostRecent,Sources.Tumblr));
					in.close();
				}catch(Exception x){
					Log.e(TAG,"doInBackground - Tumblr - HJ",x);
				}
			}
			//Forums
			getThis=prefs.getBoolean(getString(R.string.prefkey_show_forums),false);
			if(getThis){
				try{
					InputStream in=HttpFetch.fetch(getString(R.string.forum_rss),timeout);
					newEntries.addAll(ForumParser.parseForumPosts(in,mostRecent));
					in.close();
				}catch(Exception x){
					Log.e(TAG,"doInBackground - Forums",x);
				}
			}
			//Facebook
			getThis=prefs.getBoolean(getString(R.string.prefkey_show_facebook),true);
			if(getThis){
				try{
					InputStream in=HttpFetch.fetch(getString(R.string.facebook_url_rss_posts),timeout);
					newEntries.addAll(RssParser.parseEntryList(in,mostRecent,Sources.Facebook));
					in.close();
				}catch(Exception x){
					Log.e(TAG,"doInBackground - Forums",x);
				}
			}
			//TODO GooglePlus,Twitter
			//sort
	        Collections.sort(newEntries,new Comparator<StreamEntry>(){
	            public int compare(StreamEntry entry1, StreamEntry entry2){
	                return(entry1.compareTo(entry2));
	            }
	        });
	        //append
	        stream.appendListToFront(newEntries);
	        //save the entries
	        try{
    			SerializationHelper.serializeObject(stream.getEntries(),"stream.obj");
	        }catch(Exception x){
				Log.e(TAG,"doInBackground - saving entry list",x);
	        }
			return(null);
		}
		
		public void onPostExecute(Void result){
    		try{
				isUpdating=false;
   				setProgressVisibility(false);
   			}catch(Exception x){
   				Log.e(TAG,"onPostExecute",x);
   			}finally{
   				notifyDataSetChanged();
   			}
		}

		@Override
		protected void onCancelled() {
			super.onCancelled();
			isUpdating=false;
			setProgressVisibility(false);
		}
		
	}
	
	/** Called when the activity is first created. */
	@SuppressWarnings("unchecked")
	@Override
	public void onCreate(Bundle savedInstanceState){
		super.onCreate(savedInstanceState);
		try{
			//TODO - this is here for debugging only!! -- move this to onUpgrade later
//			try{
//				File f=new File(Utils.getDownloadPath()+"/stream.obj");
//				if(f.exists()){f.delete();}
//			}catch(Exception x){ }
			
			//load the view
			this.setContentView(R.layout.streamlayout);
			//setup actionbar
			ActionBar actionBar=getSupportActionBar();
			actionBar.setIcon(R.drawable.logo); 
			actionBar.setTitle("");
			//setup stream
			if(this.listViewStream==null){
				this.listViewStream=(ListView)this.findViewById(R.id.stream_listview_streamitems);
				this.listViewStream.setOnItemClickListener(selectEntryListener);
				this.listViewStream.setOnScrollListener(onScrollListener);
			}
			//why am I doing this null check on onCreate? I'm sure it seemed like a good idea at the time...
			if(this.stream==null){
				ArrayList<StreamEntry> entries=null;
				//try to load saved version from SD
				try{
					ArrayList<StreamEntry> cachedEntries=null;
					cachedEntries=(ArrayList<StreamEntry>)SerializationHelper.readObject("stream.obj");
					if(cachedEntries==null){
						entries=new ArrayList<StreamEntry>();
					}else{
						entries=cachedEntries;
					}
				}catch(Exception x){
					Log.e(TAG,"onCreate()",x);
					entries=new ArrayList<StreamEntry>();
				}
				this.stream=new StreamEntryArrayAdapter(this.getApplicationContext(),R.layout.streamlistitem,entries);
			}
			this.listViewStream.setAdapter(this.stream);
		}catch(Exception x){
			Log.e(TAG,"onCreate()",x);
			TextView errorView=new TextView(this);
			errorView.setText(x.getMessage());
			this.setContentView(errorView);
		}
	}	
	
	@Override
	protected void onResume(){
		super.onResume();
		//if the activity was paused while the background thread was running the progress may still show
		if(!isUpdating){
			setProgressVisibility(false);
		}
		this.updateStream(false);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu){
		try{
			menu.add(0,MENU_REFRESH,MENU_REFRESH,"Refresh").setIcon(R.drawable.menu_refresh);
			menu.add(0,MENU_SETTINGS,MENU_SETTINGS,"Settings").setIcon(R.drawable.menu_settings);
			menu.add(0,MENU_ABOUT,MENU_ABOUT,"About").setIcon(R.drawable.menu_about);
			//TODO - check if there are any downloads before showing this
			menu.add(0,MENU_MANAGE_DOWNLOADS,MENU_MANAGE_DOWNLOADS,"Manage downloads").setIcon(R.drawable.menu_downloads);
			menu.add(0,MENU_QUIT,MENU_QUIT,"Quit").setIcon(R.drawable.menu_quit);
			return(true);
		}catch(Exception x){
			Log.e(TAG,"onCreateOptionsMenu",x);
			return(false);
		}
	}
	
	@Override
	public boolean onOptionsItemSelected(MenuItem item){
		try{
			switch(item.getItemId()){
			case MENU_REFRESH:{this.updateStream(true); return(true);}
			case MENU_ABOUT:{this.showAboutDialog(); return(true);}
			case MENU_QUIT:{this.finish();return(true);}
			case MENU_MANAGE_DOWNLOADS:{
				Intent manageSavedEpisodesIntent=new Intent(getApplicationContext(),ManageSavedEpisodesActivity.class);
				startActivityForResult(manageSavedEpisodesIntent,0);
				return(true);
			}
			case MENU_SETTINGS:{
				Intent settingsIntent=new Intent(getApplicationContext(),SettingsActivity.class);
				startActivityForResult(settingsIntent,0);
				return(true);
			}
			default:{return(false);}
			}
		}catch(Exception x){
			if(item!=null){
				Log.e(TAG,"onOptionsItemSelected: item.getItemId()="+item.getItemId(),x);
			}else{
				Log.e(TAG,"onOptionsItemSelected: item is null",x);
			}
			return(false);
		}
	}		
	
	OnItemClickListener selectEntryListener=new OnItemClickListener(){
		@Override
		public void onItemClick(AdapterView<?> parent,View view,int position,long id){
			try{
				entryClicked(position);
			}catch(Exception x){
				Log.e(TAG,"onItemClick: position="+position,x);
				showErrorDialog(x);
			}
		}
	};
	
	//TODO - eventually figure out how to tell is the user is swiping down from the first item and check for new content
	//boolean isScrolling;
	AbsListView.OnScrollListener onScrollListener=new AbsListView.OnScrollListener(){
	    @Override
	    public void onScrollStateChanged(AbsListView view, int scrollState){
//	    	Log.d("onScrollListener","scrollState="+scrollState);
//	    	isScrolling=(scrollState==1);
	    }

	    @Override
	    public void onScroll(AbsListView view,int firstVisibleItem,int visibleItemCount,int totalItemCount){
//	    Log.d("onScrollListener ","firstVisibleItem="+firstVisibleItem+" visibleItemCount="+visibleItemCount);
//	    Log.d("onScrollListener ","isScrolling="+isScrolling);
	     }
	};
	
	private void entryClicked(int entryIndex){
		try{
			selectedEntry=this.stream.getItem(entryIndex);
			boolean openInBrowser=false;
			boolean extraInfoShowLink=false;
			boolean extraInfoRenderContent=false;
			String intentUri=null;
			switch(selectedEntry.getSource()){
			case Podcast:{
				extraInfoRenderContent=true;
				break;
			}
			case HJ:{
				break;
			}
			case Forums:{
				extraInfoRenderContent=true;
				extraInfoShowLink=true;
				break;
			}
			case Facebook:{
				openInBrowser=true;
				//TODO - figure out why this isn't launching in the Facebook app
//				if(isFacebookAppInstalled==null){
//					try{
//						ApplicationInfo info=this.getPackageManager().getApplicationInfo("com.facebook.katana",0);
//						if(info!=null){
//							isFacebookAppInstalled=Boolean.valueOf(true);
//						}else{
//							isFacebookAppInstalled=Boolean.valueOf(false);
//						}
//					}catch(PackageManager.NameNotFoundException nnfx){
//						isFacebookAppInstalled=Boolean.valueOf(false);
//					}
//				}
//				if(isFacebookAppInstalled.booleanValue()){
//					String url=selectedEntry.getUrl();
//					int lastIndexOf=url.lastIndexOf('/');
//					String postId=url.substring(lastIndexOf+1);
//					intentUri=" fb://post/"+postId;
//				}else{
					intentUri=selectedEntry.getUrl();
//				}
				break;	
			}
			case YouTube:{
				openInBrowser=true;
				intentUri=selectedEntry.getUrl();
				break;	
			}
			case Tumblr:{
				extraInfoRenderContent=true;
				break;				
			}
			case GooglePlus: break;//TODO
			case Twitter: break;//TODO
			}
			if(openInBrowser){
				if(intentUri!=null){
					Intent externalIntent=new Intent(Intent.ACTION_VIEW,Uri.parse(intentUri));
					this.startActivityForResult(externalIntent,0);
				}
			}else{//send to the view entry form
				Intent viewEntryIntent=new Intent(this.getApplicationContext(),ViewEntryActivity.class);
				viewEntryIntent.putExtra("extraInfoShowLink",extraInfoShowLink);
				viewEntryIntent.putExtra("extraInfoRenderContent",extraInfoRenderContent);
				this.startActivityForResult(viewEntryIntent,0);
			}
		}catch(Exception x){
			Log.e(TAG,"entryClicked, entryIndex="+entryIndex,x);
			this.showErrorDialog(x);
		}
	}
	
	private void notifyDataSetChanged(){
		try{
			//TODO - why did I think I needed this method?
			//			this.stream.notifyDataSetChanged();
		}catch(Exception x){
			Log.e(TAG,"notifyDataSetChanged",x);
		}
	}
	
	private void updateStream(boolean forceRefresh){
		try{
			if(!isUpdating){
				//check if the refresh interval has passed
				if(forceRefresh){
					lastRefresh=0L;
				}
				SharedPreferences prefs=this.getApplicationContext().getSharedPreferences("com.huguesjohnson.retroleague",MODE_PRIVATE);
				int refreshInterval=prefs.getInt(getString(R.string.prefkey_refresh_interval),15);
				long refreshIntervalMs=refreshInterval*60000L;
				long nextRefreshTime=lastRefresh+refreshIntervalMs;
				long now=System.currentTimeMillis();
				if(now>nextRefreshTime){
					isUpdating=true;
					this.setProgressVisibility(true);
					(new UpdateStreamTask()).execute(new Void[0]);
				}
				lastRefresh=now;
			}
		}catch(Exception x){
			Log.e(TAG,"refreshLists",x);
			this.showErrorDialog(x);
		}
	}	
	
	public static StreamEntry getSelectedEntry(){
		return(selectedEntry);
	}
	
	private void setProgressVisibility(boolean visible){
		try{
			LinearLayout progressLayout=(LinearLayout)findViewById(R.id.stream_layout_updating);
			if(visible){
				progressLayout.setVisibility(View.VISIBLE);
			}else{
				progressLayout.setVisibility(View.GONE);
			}
		}catch(Exception x){
			Log.e(TAG,"hideProgress",x);
		}
	}
	
	private void showAboutDialog(){
		try{
			//create the dialog
			if(this.aboutDialog==null){
				LayoutInflater inflater=(LayoutInflater)this.getSystemService(LAYOUT_INFLATER_SERVICE);
				View layout=inflater.inflate(R.layout.aboutdialoglayout,(ViewGroup)findViewById(R.id.AboutDialogRoot));
				AlertDialog.Builder builder=new AlertDialog.Builder(this);
				builder.setView(layout);
				builder.setTitle("About");
				builder.setPositiveButton("Close",null);
				this.aboutDialog=builder.create();
			}
			//show the dialog
			this.aboutDialog.show();
		}catch(Exception x){
			Log.e(TAG,"showAboutDialog",x);
		}	
	}		
	
	private void showErrorDialog(Exception x){
		try{
	        new AlertDialog.Builder(this)
	   		.setTitle(R.string.app_name)
	   		.setMessage("Error: "+x.getMessage())
	   		.setPositiveButton("Close", null)
	   		.show();	
		}catch(Exception reallyBadTimes){
			Log.e(TAG,"showErrorDialog",reallyBadTimes);
		}
	}

}